def ci_setup(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_ci_setup.sh",
    label: 'Set up CI environment',
  )
}

def python_unittest(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_python_unittest.sh",
    label: 'Run Python unit tests',
  )
}

def fsim_test(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_python_vta_fsim.sh",
    label: 'Run VTA tests in FSIM',
  )
}

def cmake_build(image, path, make_flag) {
  sh (
    script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_build.py --sccache-bucket tvm-sccache-prod",
    label: 'Run cmake build',
  )
}

def cpp_unittest(image) {
  sh (
    script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_cpp_unittest.sh",
    label: 'Build and run C++ tests',
  )
}

def add_microtvm_permissions() {
  {% for folder in microtvm_template_projects %}
  sh(
    script: 'find {{ folder }} -type f | grep qemu-hack | xargs chmod +x',
    label: 'Add execute permissions for microTVM files',
  )
  {% endfor %}
}

def add_hexagon_permissions() {
  {% for folder in hexagon_api %}
  sh(
    script: 'find {{ folder }} -type f | xargs chmod +x',
    label: 'Add execute permissions for hexagon files',
  )
  {% endfor %}
}

// Run make. First try to do an incremental make from a previous workspace in hope to
// accelerate the compilation. If something is wrong, clean the workspace and then
// build from scratch.
def make(docker_type, path, make_flag) {
  timeout(time: max_time, unit: 'MINUTES') {
    try {
      cmake_build(docker_type, path, make_flag)
    } catch (hudson.AbortException ae) {
      // script exited due to user abort, directly throw instead of retry
      if (ae.getMessage().contains('script returned exit code 143')) {
        throw ae
      }
      echo 'Incremental compilation failed. Fall back to build from scratch'
      sh (
        script: "${docker_run} ${docker_type} ./tests/scripts/task_clean.sh ${path}",
        label: 'Clear old cmake workspace',
      )
      cmake_build(docker_type, path, make_flag)
    }
  }
}


def build() {
stage('Build') {
  environment {
    SKIP_SLOW_TESTS = "${skip_slow_tests}"
  }
  parallel(

  {% call m.build_step(
      name='BUILD: GPU',
      node='CPU-SMALL',
      condition='!skip_ci',
      ws='tvm/build-gpu',
      docker_image='ci_gpu',
    ) %}
    sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu.sh build"
    make("${ci_gpu} --no-gpu", 'build', '-j2')
    {{ m.upload_artifacts(tag='gpu', filenames=tvm_multilib, folders=microtvm_template_projects) }}

    // compiler test
    sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh build2"
    make("${ci_gpu} --no-gpu", 'build2', '-j2')
    {{ m.upload_artifacts(tag='gpu2', filenames=tvm_multilib) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: CPU',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-cpu',
      docker_image='ci_cpu',
    ) %}
    sh (
      script: "${docker_run} ${ci_cpu} ./tests/scripts/task_config_build_cpu.sh build",
      label: 'Create CPU cmake config',
    )
    make(ci_cpu, 'build', '-j2')
    {{ m.upload_artifacts(tag='cpu', filenames=tvm_multilib_tsim) }}
    ci_setup(ci_cpu)
    // sh "${docker_run} ${ci_cpu} ./tests/scripts/task_golang.sh"
    // TODO(@jroesch): need to resolve CI issue will turn back on in follow up patch
    sh (script: "${docker_run} ${ci_cpu} ./tests/scripts/task_rust.sh", label: 'Rust build and test')
  {% endcall %}

  {% call m.build_step(
      name='BUILD: CPU MINIMAL',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-cpu-minimal',
      docker_image='ci_minimal',
    ) %}
    sh (
      script: "${docker_run} ${ci_minimal} ./tests/scripts/task_config_build_minimal.sh build",
      label: 'Create CPU minimal cmake config',
    )
    make(ci_minimal, 'build', '-j2')
    {{ m.upload_artifacts(tag='cpu-minimal', filenames=tvm_lib) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: WASM',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-wasm',
      docker_image='ci_wasm',
    ) %}
    sh (
      script: "${docker_run} ${ci_wasm} ./tests/scripts/task_config_build_wasm.sh build",
      label: 'Create WASM cmake config',
    )
    make(ci_wasm, 'build', '-j2')
    cpp_unittest(ci_wasm)
    ci_setup(ci_wasm)
    sh (
      script: "${docker_run} ${ci_wasm} ./tests/scripts/task_web_wasm.sh",
      label: 'Run WASM lint and tests',
    )
  {% endcall %}

  {% call m.build_step(
      name='BUILD: i386',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-i386',
      docker_image='ci_i386',
    ) %}
    sh (
      script: "${docker_run} ${ci_i386} ./tests/scripts/task_config_build_i386.sh build",
      label: 'Create i386 cmake config',
    )
    make(ci_i386, 'build', '-j2')
    {{ m.upload_artifacts(tag='i386', filenames=tvm_multilib_tsim) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: arm',
      node='ARM-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-arm',
      docker_image='ci_arm',
    ) %}
    sh (
      script: "${docker_run} ${ci_arm} ./tests/scripts/task_config_build_arm.sh build",
      label: 'Create ARM cmake config',
    )
    make(ci_arm, 'build', '-j4')
    {{ m.upload_artifacts(tag='arm', filenames=tvm_multilib) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: Cortex-M',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-cortexm',
      docker_image='ci_cortexm',
    ) %}
    sh (
      script: "${docker_run} ${ci_cortexm} ./tests/scripts/task_config_build_cortexm.sh build",
      label: 'Create Cortex-M cmake config',
    )
    make(ci_cortexm, 'build', '-j2')
    {{ m.upload_artifacts(tag='cortexm', filenames=tvm_lib, folders=microtvm_template_projects) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: Hexagon',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-hexagon',
      docker_image='ci_hexagon',
    ) %}
    sh (
      script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_config_build_hexagon.sh build",
      label: 'Create Hexagon cmake config',
    )
    make(ci_hexagon, 'build', '-j2')
    sh (
      script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_build_hexagon_api.sh",
      label: 'Build Hexagon API',
    )
    {{ m.upload_artifacts(tag='hexagon', filenames=tvm_lib, folders=hexagon_api) }}
  {% endcall %}

  {% call m.build_step(
      name='BUILD: RISC-V',
      node='CPU-SMALL',
      condition='!skip_ci && is_docs_only_build != 1',
      ws='tvm/build-riscv',
      docker_image='ci_riscv',
    ) %}
    sh (
      script: "${docker_run} ${ci_riscv} ./tests/scripts/task_config_build_riscv.sh build",
      label: 'Create RISC-V cmake config',
    )
    make(ci_riscv, 'build', '-j2')
    {{ m.upload_artifacts(tag='riscv', filenames=tvm_lib, folders=microtvm_template_projects) }}
  {% endcall %}

  )
}
}
